﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JYH.Data;
using Newtonsoft.Json;
using JYH.Model;
using JYH.DataAccess;
using JYH.Framework;
using JYH.Model.API;
using System.Data;


namespace JYH.Business
{
    /// <summary>
    ///  BasBarcodeInfo
    /// </summary>
    public class BasBarcodeInfoBLL : BusinessBase<BasBarcodeInfo>
    {
        /// <summary>
        ///  BasBarcodeInfo
        /// </summary>
        public BasBarcodeInfoBLL()
        {
            myDataBase = DB.D();
            this.SqlSelect = @";SELECT
	                        BasBarcodeInfo.*,
	                        BasMaterialInfo.MaterialNO,
	                        BasMaterialInfo.MaterialDesc,
	                        BasMaterialInfo.MaterialName,
	                        BasPartnerInfo.PartnerNO,
	                        BasPartnerInfo.PartnerName,
	                        WmsReciveOrderInfo.ReciveOrderNO,
                            WmsReciveItem.ErpItem
                        FROM
	                        BasBarcodeInfo
	                        INNER JOIN BasMaterialInfo ON BasMaterialInfo.MaterialID= BasBarcodeInfo.MaterialID
	                        LEFT JOIN BasPartnerInfo ON BasPartnerInfo.PartnerID= BasBarcodeInfo.PartnerID
	                        LEFT JOIN WmsReciveItem ON BasBarcodeInfo.SourceOrderID= WmsReciveItem.ReciveItemID
	                        LEFT JOIN WmsReciveOrderInfo ON WmsReciveOrderInfo.ReciveOrderID= WmsReciveItem.ReciveOrderID";
        }

        /// <summary>
        /// 条码生成（批量）
        /// </summary>
        /// <param name="info">条码对象</param>
        /// <param name="message">返回信息</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public bool SaveBarcodeInfo(List<BasBarcodeInfo> info, ref ResponseJson<BasBarcodeInfo> message)
        {
            string Msg = string.Empty;
            myDataBase.BeginTransaction();
            StringBuilder sb = new StringBuilder();
            decimal[] qtys;
            Sql sql = new Sql();
            try
            {
                #region 获取收料明细对象

                string ReciveItemIDList = "'',";
                for (int i = 0; i < info.Count; i++)
                {
                    ReciveItemIDList += "'" + info[i].ReciveItemID + "',";
                }
                //去掉最后一个逗号
                ReciveItemIDList = ReciveItemIDList.Substring(0, ReciveItemIDList.Length - 1);
                WmsReciveItemBLL wmsReciveItem = new WmsReciveItemBLL();
                sql.Append(wmsReciveItem.SqlSelect);
                sql.Append($"Where WmsReciveItem.ReciveItemID in ({ReciveItemIDList}) order by WmsReciveItem.CreateTime desc");
                List<WmsReciveItem> reciveItemList = myDataBase.Fetch<WmsReciveItem>(sql);

                BasMaterialInfo material = new BasMaterialInfo();
                sql = new Sql();
                sql.Append(";Select BasMaterialInfo.* From BasMaterialInfo");
                sql.Where("(BasMaterialInfo.MaterialID='" + info[0].MaterialID + "' or BasMaterialInfo.MaterialNO='" + info[0].MaterialNO + "')");
                material = myDataBase.FirstOrDefault<BasMaterialInfo>(sql);
                BasPartnerInfo partner = new BasPartnerInfo();
                sql = new Sql();
                sql.Append(";Select BasPartnerInfo.* From BasPartnerInfo");
                sql.Where("BasPartnerInfo.PartnerID='" + info[0].PartnerID + "'");
                partner = myDataBase.FirstOrDefault<BasPartnerInfo>(sql);

                #endregion 获取收料明细对象


                int cout = 0;
                for (int i = 0; i < info.Count; i++)
                {
                    int indexs = -1;
                    //收料明细对象
                    indexs = reciveItemList.FindIndex(x => x.ReciveItemID == info[i].ReciveItemID);

                    //生成条码
                    qtys = GenerateQuantityArray(info[i].Qty, info[i].PackQty, info[i].Quantity);

                    decimal temp = 0.0m;
                    for (int j = 0; j < qtys.Length; j++)
                    {
                        BasBarcodeInfo basBarcode = new BasBarcodeInfo();
                        basBarcode.BarcodeID = Guid.NewGuid().ToString();
                        basBarcode.BarcodeNO = SysFormNOInfoBLL.GetLastFormNO("BarcodeNO", out Msg);
                        basBarcode.Qty = qtys[j];
                        if (reciveItemList == null || reciveItemList.Count == 0)
                        {
                            basBarcode.MaterialID = material.MaterialID;
                            basBarcode.MaterialNO = material.MaterialNO;
                            basBarcode.MaterialName = material.MaterialName;
                            basBarcode.MaterialDesc = material.MaterialDesc;
                            if (partner != null)
                            {
                                basBarcode.PartnerID = partner.PartnerID;
                            }
                        }
                        else
                        {
                            basBarcode.PartnerID = reciveItemList[indexs].PartnerID;
                            basBarcode.MaterialID = reciveItemList[indexs].MaterialID;
                            basBarcode.SourceOrderID = reciveItemList[indexs].ReciveItemID;
                            sb.Append(@"update WmsReciveOrderInfo set RState='4' where ReciveOrderID='"+ reciveItemList[indexs].ReciveOrderID+ "' And RState='2'");
                        }

                        basBarcode.BatchNO = info[i].BatchNO;
                        basBarcode.CreateUser = info[0].CreateUser; ;
                        basBarcode.Humidity = info[i].Humidity;
                        message.Items.Add(basBarcode);
                        sb.Append(BusinessTool.GetInsertSql(basBarcode));
                        temp += basBarcode.Qty;
                        //if (indexs > -1)
                        //{
                        //    flag = true;
                        //    reciveItemList[indexs].LabelQty -= qtys[j];
                        //}
                        cout++;
                    }
                    qtys = new decimal[0];
                    if (indexs >= 0)
                    {
                        reciveItemList[indexs].LabelQty = reciveItemList[indexs].LabelQty - temp;
                        sb.Append(BusinessTool.GetUpdateSql(reciveItemList[indexs]));
                    }

                    cout++;
                   
                    if (cout >= 500)
                    {
                        if (sb.Length > 0)
                        {
                            myDataBase.Execute(sb.ToString());
                            sb.Clear(); // 清空 StringBuilder
                        }
                        cout = 0; // 重置计数器
                    }
                }
                if (sb.Length > 0)
                {
                    myDataBase.Execute(sb.ToString());
                }
                myDataBase.CompleteTransaction();
            }
            catch (Exception ex)
            {
                myDataBase.AbortTransaction();
                message.Message = ex.Message;
                return false;
            }
            return true;
        }

        /// <summary>
        /// 将 Qty 按照 PackQty 分组，返回每包的数量数组。
        /// 如果 generateCount > 0，则生成指定份数，但不会填充 0。
        /// </summary>
        /// <param name="qty">总数量，例如要分装的物料总数</param>
        /// <param name="packQty">每包的标准数量，即每次分装的单位量</param>
        /// <param name="generateCount">包装份数</param>
        /// <returns>返回一个 decimal 类型的数组，表示每一份分装的具体数量</returns>
        public static decimal[] GenerateQuantityArray(decimal qty, decimal packQty, decimal generateCount)
        {
            // 校验 PackQty 是否合法，必须大于 0
            if (packQty <= 0)
                throw new ArgumentException("PackQty 必须大于 0");

            // 校验 generateCount 是否合法，不能为负数
            if (generateCount < 0)
                throw new ArgumentException("generateCount 不能为负数");

            // 用于存储分装后的每份数量
            List<decimal> quantities = new List<decimal>();

            if (generateCount == 0)
            {
                // 默认逻辑：根据 qty 和 packQty 自动计算需要分成多少份

                // 计算可以完整分装的份数（向下取整）
                decimal fullPackages = Math.Floor(qty / packQty);

                // 计算剩余的数量（余数）
                decimal remainder = qty % packQty;

                // 添加完整的每一份 packQty
                for (decimal i = 0; i < fullPackages; i++)
                {
                    quantities.Add(packQty);
                    qty -= packQty; // 减去已分装部分
                }

                // 如果还有余数，添加最后一份小批量
                if (remainder > 0)
                {
                    quantities.Add(remainder);
                }
            }
            else
            {
                // 强制分装逻辑：最多生成 generateCount 份，不补 0

                // 循环直到达到指定份数 或 数量已分完
                for (int i = 0; i < generateCount && qty > 0; i++)
                {
                    if (qty >= packQty)
                    {
                        quantities.Add(packQty); // 添加完整的一份
                        qty -= packQty;          // 扣除对应数量
                    }
                    else
                    {
                        quantities.Add(qty);     // 添加剩余的小份
                        qty = 0;                 // 剩余数量清零
                    }
                }
            }

            // 返回最终的分装结果数组
            return quantities.ToArray();
        }

        /// <summary>
        /// 获取打印物料条码信息
        /// </summary>
        /// <param name="IDs">条码对象</param>
        /// <param name="printQty">0 第一次打印 1补打</param>
        /// <param name="Msg"></param>
        /// <returns></returns>
        public DataSet GetWmsBarCodeInfo(string IDs, string printQty, out string Msg)
        {
            Sql sql = new Sql();
            sql.Append(this.SqlSelect);
            if (!string.IsNullOrEmpty(IDs))
            {
                IDs = IDs.Substring(0, IDs.Length - 1);
                string sqls = string.Empty;
                string[] strs = IDs.Split(',');
                for (int i = 0; i < strs.Length; i++)
                {
                    sqls += "'" + strs[i].ToString() + "',";
                }
                sqls = sqls.Substring(0, sqls.Length - 1);
                sql.Append("WHERE BasBarcodeInfo.BarcodeID in (" + sqls + ")");
            }
            sql.OrderBy("BasBarcodeInfo.BarcodeNO desc");
            Msg = string.Empty;
            DataSet ds = new DataSet();
            myDataBase.Fill(ds, sql.SQL, null);
            if (ds != null)
            {
                if (ds.Tables.Count > 0)
                {
                    ds.Tables[0].TableName = "BasBarcodeInfo";
                }
            }
            if (printQty == "0")
            {
                //  补打
                UpdateBarcodeInfo(ds);
            }
            return ds;
        }

        /// <summary>
        /// First print
        /// </summary>
        /// <param name="ds"></param>
        private void UpdateBarcodeInfo(DataSet ds)
        {
            List<BasBarcodeInfo> barcodeInfos = BusinessTool.TableToListModel<BasBarcodeInfo>(ds.Tables[0]);
            // 提取所有 BarcodeID
            var barcodeIds = barcodeInfos.Select(b => $"'{b.BarcodeID}'").ToList();

            // 构建 SQL：批量增加 Prints 字段值
            string sql_updtaes = $@"
                         UPDATE BasBarcodeInfo
                         SET Prints = Prints + 1
                         WHERE BarcodeID IN ({string.Join(",", barcodeIds)})";

            myDataBase.Execute(sql_updtaes);
        }

        /// <summary>
        /// 库存条码拆包
        /// </summary>
        /// <param name="info">包含 BarcodeID 和 Qty（要拆出的数量）</param>
        /// <param name="json">返回结果</param>
        /// <returns></returns>
        public bool CodeUnPack(BasBarcodeInfo info, ref ResponseJson<BasBarcodeInfo> json)
        {
            Database db = DB.D();
            db.BeginTransaction();
            StringBuilder sb = new StringBuilder();
            try
            {
                #region 基础条码拆包

                Sql sql = new Sql();
                sql.Append($"SELECT * FROM BasBarcodeInfo WHERE BarcodeNO ='{info.BarcodeNO}'");
                var barcodeInfo = db.FirstOrDefault<BasBarcodeInfo>(sql);
                if (barcodeInfo == null)
                {
                    json.Message = ErrorCode.NoExistBarcode.GetMessage(info.BarcodeNO);
                    return false;
                }
                // 3. 创建第一个新条码（剩余部分）
                var remainBarcode = new BasBarcodeInfo
                {
                    BarcodeID = Guid.NewGuid().ToString(),
                    BarcodeNO = SysFormNOInfoBLL.GetLastFormNO("BarcodeNO", out string msg),
                    MaterialID = barcodeInfo.MaterialID,
                    MaterialNO = barcodeInfo.MaterialNO,
                    MaterialName = barcodeInfo.MaterialName,
                    MaterialDesc = barcodeInfo.MaterialDesc,
                    PartnerID = barcodeInfo.PartnerID,
                    SourceOrderID = barcodeInfo.SourceOrderID,
                    BatchNO = barcodeInfo.BatchNO,
                    Qty = info.NewQty,
                    IsStock = 1,
                    Humidity = barcodeInfo.Humidity,
                    CreateUser = info.CreateUser
                };
                // 4. 修改旧条码（拆出部分）
                barcodeInfo.Qty -= info.NewQty;
                barcodeInfo.Prints = 0;
                barcodeInfo.IsStock = 1;
                // 6. 插入两个新条码
                sb.Append(BusinessTool.GetInsertSql(remainBarcode));
                sb.Append(BusinessTool.GetUpdateSql(barcodeInfo));

                #endregion 基础条码拆包

                #region 库存条码拆包

                WmsStockBarcodeBLL wmsStock = new WmsStockBarcodeBLL();
                sql = new Sql();
                sql.Append(wmsStock.SqlSelect);
                sql.Append("Where BasBarcodeInfo.BarcodeID='" + barcodeInfo.BarcodeID + "'");
                var stockBarcode = db.FirstOrDefault<WmsStockBarcode>(sql);
                if (stockBarcode != null)
                {
                    // 3. 创建第一个新条码（剩余部分）
                    var NewStock = new WmsStockBarcode
                    {
                        StockBarcodeID = Guid.NewGuid().ToString(),
                        BarcodeID = remainBarcode.BarcodeID,
                        BarcodeNO = remainBarcode.BarcodeNO,
                        MaterialID = remainBarcode.MaterialID,
                        BatchNO = remainBarcode.BatchNO,
                        StockQty = remainBarcode.Qty,
                        WarehouseID = stockBarcode.WarehouseID,
                        StorageID = stockBarcode.StorageID,
                        LampID = stockBarcode.LampID,
                        CreateUser = remainBarcode.CreateUser,
                        IsLock = 0
                    };
                    if (!string.IsNullOrEmpty(info.TradeOrderNO))
                        NewStock.IsLock = 1;
                    // 4. 修改旧条码（拆出部分）
                    stockBarcode.StockQty -= barcodeInfo.Qty;

                    // 6. 插入两个新条码
                    sb.Append(BusinessTool.GetInsertSql(NewStock));
                    sb.Append(BusinessTool.GetUpdateSql(stockBarcode));
                }

                #endregion 库存条码拆包

                #region 交易条码拆包

                if (!string.IsNullOrEmpty(info.TradeOrderNO))
                {
                    WmsTradebarcodeBLL wmsTrade = new WmsTradebarcodeBLL();
                    sql = new Sql();
                    sql.Append(wmsTrade.SqlSelect);
                    sql.Append($"Where  WmsTradeOrderInfo.TradeOrderNO='{info.TradeOrderNO}' And BasBarcodeInfo.BarcodeID='{barcodeInfo.BarcodeID}'");
                    var tradeBarcode = db.FirstOrDefault<WmsTradebarcode>(sql);
                    if (tradeBarcode == null)
                    {
                        db.AbortTransaction();
                        json.Message = ErrorCode.NoExistBarcode.GetMessage(info.BarcodeNO);
                        return false;
                    }
                    tradeBarcode.BarcodeID = remainBarcode.BarcodeID;
                    tradeBarcode.Qty = remainBarcode.Qty;
                    sb.Append(BusinessTool.GetUpdateSql(tradeBarcode));
                }

                #endregion 交易条码拆包

                // 7. 执行 SQL
                if (sb.Length > 0)
                {
                    db.Execute(sb.ToString());
                }
                json.Items.Add(remainBarcode);
                db.CompleteTransaction();
                return true;
            }
            catch (Exception ex)
            {
                db.AbortTransaction();
                json.Message = ex.Message;
                return false;
            }
        }


        /// <summary>
        /// 批量删除条码
        /// </summary>
        /// <param name="list">条码集合</param>
        /// <param name="Msg">反馈信息</param>
        /// <returns></returns>
        public bool DeleteBarcode(List<BasBarcodeInfo> list, out string Msg)
        {
            Msg="Action Access";
            try
            {
                Database db = DB.D();
                string BarcodeID = "'',";
                foreach (BasBarcodeInfo barcode in list)
                {
                    BarcodeID += "'"+ barcode.BarcodeID + "',";
                }
                BarcodeID = BarcodeID.Substring(0, BarcodeID.Length - 1);
                Sql sql = new Sql();
                sql.Append("Select WmsPreparatBarcode.* From WmsPreparatBarcode");
                sql.Where("WmsPreparatBarcode.BarcodeID in (" + BarcodeID + ")");
                DataTable dt = new DataTable();
                db.Fill(dt, sql.SQL, null);
                if (dt != null && dt.Rows.Count > 0) 
                {
                    Msg = "";
                    return false;
                }
                sql = new Sql();
                sql.Append("Select WmsStockBarcode.* From WmsStockBarcode");
                sql.Where("WmsStockBarcode.BarcodeID in (" + BarcodeID + ")");
                 dt = new DataTable();
                db.Fill(dt, sql.SQL, null);
                if (dt != null && dt.Rows.Count > 0)
                {
                    Msg = "";
                    return false;
                }

                sql = new Sql();
                sql.Append("Select WmsTradebarcode.* From WmsTradebarcode");
                sql.Where("WmsTradebarcode.BarcodeID in (" + BarcodeID + ")");
                dt = new DataTable();
                db.Fill(dt, sql.SQL, null);
                if (dt != null && dt.Rows.Count > 0)
                {
                    Msg = "";
                    return false;
                }
                sql = new Sql();
                sql.Append("Delete BasBarcodeInfo Where BarcodeID in (" + BarcodeID + ")");
                db.Execute(sql.SQL);
                return true;
            }
            catch(Exception ex) 
            {
                Msg = ex.Message;
                return false;
            }

        }


        /// <summary>
        /// 批量删除条码
        /// </summary>
        /// <param name="list">条码集合</param>
        /// <param name="Msg">反馈信息</param>
        /// <returns></returns>
        public bool DeleteBarcode(List<BasBarcodeInfo> list, Database db, out string Msg)
        {
            Msg = "Action Access";
            try
            {
    
                string BarcodeID = "'',";
                foreach (BasBarcodeInfo barcode in list)
                {
                    BarcodeID += "'" + barcode.BarcodeID + "',";
                }
                BarcodeID = BarcodeID.Substring(0, BarcodeID.Length - 1);
                Sql sql = new Sql();
                sql.Append("Select WmsPreparatBarcode.* From WmsPreparatBarcode");
                sql.Where("WmsPreparatBarcode.BarcodeID in (" + BarcodeID + ")");
                DataTable dt = new DataTable();
                db.Fill(dt, sql.SQL, null);
                if (dt != null && dt.Rows.Count > 0)
                {
                    Msg = "";
                    return false;
                }
                sql = new Sql();
                sql.Append("Select WmsStockBarcode.* From WmsStockBarcode");
                sql.Where("WmsStockBarcode.BarcodeID in (" + BarcodeID + ")");
                dt = new DataTable();
                db.Fill(dt, sql.SQL, null);
                if (dt != null && dt.Rows.Count > 0)
                {
                    Msg = "";
                    return false;
                }

                sql = new Sql();
                sql.Append("Select WmsTradebarcode.* From WmsTradebarcode");
                sql.Where("WmsTradebarcode.BarcodeID in (" + BarcodeID + ")");
                dt = new DataTable();
                db.Fill(dt, sql.SQL, null);
                if (dt != null && dt.Rows.Count > 0)
                {
                    Msg = "";
                    return false;
                }
                sql = new Sql();
                sql.Append("Delete BasBarcodeInfo Where BarcodeID in (" + BarcodeID + ")");
                db.Execute(sql.SQL);
                return true;
            }
            catch (Exception ex)
            {
                Msg = ex.Message;
                return false;
            }

        }

        /// <summary>
        /// 依据收料单查询
        /// </summary>
        /// <param name="ReciveOrderNO">收料单号(不允许为空)</param>
        /// <param name="ReciveItemID">收料明细ID</param>
        /// <param name="Msg"></param>
        /// <returns></returns>
        public List<BasBarcodeInfo> GetBarcodeByReceiveOrder(string ReciveOrderNO, string ReciveItemID,out string Msg)
        {
            Msg=string.Empty;
            List<BasBarcodeInfo> list = new List<BasBarcodeInfo>();
            try
            {
                Database db = DB.D();
                if (string.IsNullOrEmpty(ReciveOrderNO))
                {
                    Msg = "ReciveOrderNO Cannot Be Empty";
                    return list=new List<BasBarcodeInfo>();
                }
                Sql sql = new Sql();
                sql.Append(this.SqlSelect);
                sql.Where("(WmsReciveOrderInfo.ReciveOrderID ='" + ReciveOrderNO + "' or WmsReciveOrderInfo.ReciveOrderNO='" + ReciveOrderNO + "')");
                if (!string.IsNullOrEmpty(ReciveItemID))
                {
                    sql.Where(" WmsReciveItem.ReciveItemID='"+ReciveItemID+"'");
                }
                sql.OrderBy("BasBarcodeInfo.BarcodeNO desc");
                list= db.Fetch<BasBarcodeInfo>(sql);
                if (list==null|| list.Count < 1) 
                {
                    Msg = " NO Records";
                }
                return list;
            } 
            catch (Exception ex)
            { 
                Msg = ex.Message;
                list = new List<BasBarcodeInfo>();
                return list;
            }
        }


        /// <summary>
        /// 依据收料单查询
        /// </summary>
        /// <param name="db">数据库对象</param>
        /// <param name="ReciveOrderNO">收料单号(不允许为空)</param>
        /// <param name="ReciveItemID">收料明细ID</param>
        /// <param name="Msg"></param>
        /// <returns></returns>
        public List<BasBarcodeInfo> GetBarcodeByReceiveOrder(Database db,string ReciveOrderNO, string ReciveItemID, out string Msg)
        {
            Msg = string.Empty;
            List<BasBarcodeInfo> list = new List<BasBarcodeInfo>();
            try
            {
           
                if (string.IsNullOrEmpty(ReciveOrderNO))
                {
                    Msg = "ReciveOrderNO Cannot Be Empty";
                    return list = new List<BasBarcodeInfo>();
                }
                Sql sql = new Sql();
                sql.Append(this.SqlSelect);
                sql.Where("(WmsReciveOrderInfo.ReciveOrderID ='" + ReciveOrderNO + "' or WmsReciveOrderInfo.ReciveOrderNO='" + ReciveOrderNO + "')");
                if (!string.IsNullOrEmpty(ReciveItemID))
                {
                    sql.Where(" WmsReciveItem.ReciveItemID='" + ReciveItemID + "'");
                }
                sql.OrderBy("BasBarcodeInfo.BarcodeNO desc");
                list = db.Fetch<BasBarcodeInfo>(sql);
                if (list == null || list.Count < 1)
                {
                    Msg = " NO Records";
                }
                return list;
            }
            catch (Exception ex)
            {
                Msg = ex.Message;
                list = new List<BasBarcodeInfo>();
                return list;
            }
        }

    }
}